package com.bmf.module.examination.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bmf.core.result.PageResponse;
import com.bmf.enums.ExaminationTypeEnum;
import com.bmf.module.examination.entity.*;
import com.bmf.module.examination.mapper.ExaminationMapper;
import com.bmf.module.examination.service.*;
import com.bmf.module.examination.vo.BigQuestionTestPaperResultVo;
import com.bmf.module.examination.vo.ExaminationCreateVo;
import com.bmf.module.examination.vo.ExaminationPageVo;
import com.bmf.module.examination.vo.ExaminationResultVo;
import com.bmf.module.testQuestions.entity.SmallQuestion;
import com.bmf.module.testQuestions.entity.SmallQuestionAnswer;
import com.bmf.module.testQuestions.service.SmallQuestionService;
import com.bmf.module.testQuestions.vo.QuestionResultVo;
import com.bmf.module.testQuestions.vo.QuestionTestPaperResultVo;
import com.bmf.utils.BeanCopyUtils;
import com.bmf.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * (Examination)表服务实现类
 *
 * @author makejava
 * @since 2022-11-29 17:54:33
 */
@Service("examinationService")
public class ExaminationServiceImpl extends ServiceImpl<ExaminationMapper, Examination> implements ExaminationService {

    @Autowired
    private FixedTestQuestionService fixedTestQuestionService;

    @Autowired
    private ExaminationService examinationService;

    @Autowired
    private BigQuestionService bigQuestionService;

    @Autowired
    private SelectionStrategyService selectionStrategyService;

    @Autowired
    private SelectionStrategyQuestionService selectionStrategyQuestionService;

    @Autowired
    private SmallQuestionService smallQuestionService;

    @Autowired
    private TestinfoService testinfoService;

    ///12345
    @Override
    public Integer insert(ExaminationCreateVo examinationCreateVo) {
        Examination examination = BeanCopyUtils.copyBean(examinationCreateVo, Examination.class);
        examination.setCreateId(SecurityUtils.getUserId());
        save(examination);
        return examination.getId();
    }

    @Override
    public PageResponse<ExaminationResultVo> selectAll(ExaminationPageVo examinationPageVo) {
        LambdaQueryWrapper<Examination> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Examination::getCreateId, SecurityUtils.getUserId());
        if(StrUtil.isNotBlank(examinationPageVo.getName())){
            wrapper.like(Examination::getName, examinationPageVo.getName());
        }
        if(examinationPageVo.getType()!=null){
            wrapper.eq(Examination::getType, examinationPageVo.getType());
        }
        if(examinationPageVo.getMold()!=null){
            wrapper.eq(Examination::getMold, examinationPageVo.getMold());
        }
        Page<Examination> page = new Page(examinationPageVo.getPageNo(),examinationPageVo.getPageSize());
        page(page,wrapper);
        List<Examination> records = page.getRecords();
        if(CollUtil.isEmpty(records)){
            return new PageResponse<>(null,page.getTotal(),examinationPageVo.getPageNo(),examinationPageVo.getPageSize());
        }
        //计算试卷总分
        List<ExaminationResultVo> examinationResultVos = BeanCopyUtils.copyBeanList(records, ExaminationResultVo.class);
        this.countExaminationTotalScore(examinationResultVos);
        return new PageResponse<>(examinationResultVos,page.getTotal(),examinationPageVo.getPageNo(),examinationPageVo.getPageSize());
    }

    @Override
    public double countTotalScore(Integer testInfoId) {
        Testinfo byId = testinfoService.getById(testInfoId);
        if(byId==null){
            return 0;
        }
        Examination byId1 = examinationService.getById(byId.getExaminationId());
        if(byId1==null){
            return 0;
        }
        List<Integer> ids = new ArrayList<>();
        ids.add(byId1.getId());
        if(byId1.getMold()==ExaminationTypeEnum.RANDOM.getCode()){
            //随机试卷
            List<SelectionStrategy> list = selectionStrategyService.getByExaminationIds(ids);
            if(CollUtil.isEmpty(list)){
                return 0;
            }
             return list.stream().mapToDouble(s -> s.getScore() * (s.getDifficulty() + s.getUnlimitedDifficulty() + s.getSecondary() + s.getEasily())).sum();
        }

        //固定试卷
        List<FixedTestQuestion> list = fixedTestQuestionService.getByExaminationIds(ids);
        if(CollUtil.isEmpty(list)){
            return 0;
        }
        return list.stream().mapToDouble(FixedTestQuestion::getScore).sum();
    }

    private void countExaminationTotalScore(List<ExaminationResultVo> examinationResultVos) {
        Map<Integer, List<ExaminationResultVo>> moldMap = examinationResultVos.stream().collect(Collectors.groupingBy(ExaminationResultVo::getMold));
        //1.计算随机试卷分数
        List<ExaminationResultVo> examinationResultVos1 = moldMap.get(ExaminationTypeEnum.RANDOM.getCode());
        if(CollUtil.isNotEmpty(examinationResultVos1)){
            List<Integer> ids = examinationResultVos1.stream().map(ExaminationResultVo::getId).collect(Collectors.toList());
            List<SelectionStrategy> list = selectionStrategyService.getByExaminationIds(ids);
            if(CollUtil.isNotEmpty(list)){
                //1.1策略分类
                Map<Integer, List<SelectionStrategy>> map = list.stream().collect(Collectors.groupingBy(SelectionStrategy::getExaminationId));
                //1.2计算试卷分数
                examinationResultVos.stream().filter(s->s.getMold()==ExaminationTypeEnum.RANDOM.getCode()).forEach(s->{
                    List<SelectionStrategy> selectionStrategies = map.get(s.getId());
                    if(CollUtil.isNotEmpty(selectionStrategies)){
                        double sum = selectionStrategies.stream()
                                .mapToDouble(k -> (k.getDifficulty() + k.getUnlimitedDifficulty() + k.getSecondary() + k.getEasily()) * k.getScore()).sum();
                        s.setTotalScore(sum);
                    }
                });
            }
        }
        //2.计算固定试卷分数
        List<ExaminationResultVo> examinationResultVos2 = moldMap.get(ExaminationTypeEnum.RANDOM.getCode());
        if(CollUtil.isNotEmpty(examinationResultVos2)){
            //2.1取得固定试卷ids
            List<Integer> ids = examinationResultVos2.stream().map(ExaminationResultVo::getId).collect(Collectors.toList());
            //2.2查询固定试题
            List<FixedTestQuestion> list = fixedTestQuestionService.getByExaminationIds(ids);
            //2.3计算试卷总分数
            if(CollUtil.isNotEmpty(list)){
                Map<Integer, List<FixedTestQuestion>> map = list.stream().collect(Collectors.groupingBy(FixedTestQuestion::getExaminationId));
                examinationResultVos2.forEach(s->{
                    List<FixedTestQuestion> fixedTestQuestions = map.get(s.getId());
                    if(CollUtil.isNotEmpty(fixedTestQuestions)){
                        double sum = fixedTestQuestions.stream().mapToDouble(FixedTestQuestion::getScore).sum();
                        s.setTotalScore(sum);
                    }
                });
            }
        }
    }

    public List<BigQuestionTestPaperResultVo> getExamination(Integer examinationId){
        if(examinationId==null){
            return null;
        }
        Examination byId = examinationService.getById(examinationId);
        Integer mold = byId.getMold();
        //查询大题
        LambdaQueryWrapper<BigQuestion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BigQuestion::getExaminationId, examinationId);
        List<BigQuestion> list = bigQuestionService.list(wrapper);
        if(CollUtil.isEmpty(list)){
            return null;
        }
        List<Integer> bigQuestionIds = list.stream().map(BigQuestion::getId).collect(Collectors.toList());
        List<BigQuestionTestPaperResultVo> bigQuestionTestPaperResultVos = BeanCopyUtils.copyBeanList(list, BigQuestionTestPaperResultVo.class);
        if(mold==2){
            //随机试卷
            //查询抽题管理
            LambdaQueryWrapper<SelectionStrategy> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.in(SelectionStrategy::getBigQuestionId, bigQuestionIds);
            List<SelectionStrategy> selectionStrategies = selectionStrategyService.list(wrapper2);
            if(CollUtil.isNotEmpty(selectionStrategies)){
                getQuestion(bigQuestionTestPaperResultVos,selectionStrategies);
            }
            return bigQuestionTestPaperResultVos;
        }
        //固定试卷
        LambdaQueryWrapper<FixedTestQuestion> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.in(FixedTestQuestion::getBigQuestionId,bigQuestionIds);
        List<FixedTestQuestion> list1 = fixedTestQuestionService.list(wrapper1);
        if(CollUtil.isNotEmpty(list1)){
            List<Integer> collect = list1.stream().map(FixedTestQuestion::getSmallQuestionId).collect(Collectors.toList());
            Map<Integer, List<FixedTestQuestion>> map = list1.stream().collect(Collectors.groupingBy(FixedTestQuestion::getBigQuestionId));
            List<QuestionResultVo> questionResultVos = smallQuestionService.selectByIds(collect);
            if(CollUtil.isNotEmpty(questionResultVos)){
                Map<Integer, QuestionResultVo> collect1 = questionResultVos.stream().collect(Collectors.toMap(QuestionResultVo::getId, Function.identity()));
                bigQuestionTestPaperResultVos.forEach(s->{
                    List<FixedTestQuestion> fixedTestQuestions = map.get(s.getId());
                    if(CollUtil.isNotEmpty(fixedTestQuestions)){
                        List<QuestionTestPaperResultVo> questionTestPaperResultVos = fixedTestQuestions.stream().map(k -> {
                            QuestionResultVo questionResultVo = collect1.get(k.getSmallQuestionId());
                            QuestionTestPaperResultVo questionTestPaperResultVo = BeanCopyUtils.copyBean(questionResultVo, QuestionTestPaperResultVo.class);
                            if (CollUtil.isNotEmpty(questionResultVo.getSmallQuestionAnswers())) {
                                List<SmallQuestionAnswer> smallQuestionAnswers = BeanCopyUtils.copyBeanList(questionResultVo.getSmallQuestionAnswers(), SmallQuestionAnswer.class);
                                questionTestPaperResultVo.setSmallQuestionAnswers(smallQuestionAnswers);
                            }
                            return questionTestPaperResultVo;
                        }).collect(Collectors.toList());
                        s.setQuestionTestPaperResultVos(questionTestPaperResultVos);
                    }
                });
            }
        }
        return bigQuestionTestPaperResultVos;
    }

    private void getQuestion(List<BigQuestionTestPaperResultVo> bigQuestionTestPaperResultVos, List<SelectionStrategy> selectionStrategies) {
        Map<Integer, List<SelectionStrategy>> map = selectionStrategies.stream().collect(Collectors.groupingBy(SelectionStrategy::getBigQuestionId));
        List<Integer> ids = selectionStrategies.stream().map(SelectionStrategy::getId).collect(Collectors.toList());
        if(CollUtil.isEmpty(ids)){
            return;
        }
        LambdaQueryWrapper<SelectionStrategyQuestion> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.in(SelectionStrategyQuestion::getExaminationId,selectionStrategies.get(0).getExaminationId());
        List<SelectionStrategyQuestion> list = selectionStrategyQuestionService.list(wrapper1);
        Map<Integer, List<SelectionStrategyQuestion>> collect = list.stream().collect(Collectors.groupingBy(SelectionStrategyQuestion::getSelectionStrategyId));
        //所有选题ids
        List<Integer> idsList = list.stream().map(SelectionStrategyQuestion::getSmallQuestionId).filter(s->s!=null).collect(Collectors.toList());
        bigQuestionTestPaperResultVos.forEach(s->{
            List<SelectionStrategy> selectionStrategies1 = map.get(s.getId());
            if(CollUtil.isNotEmpty(selectionStrategies1)){
                //添加题目
                for (SelectionStrategy selectionStrategy : selectionStrategies1) {
                    List<QuestionTestPaperResultVo> questionAndAnswer = getQuestionAndAnswer(collect.get(selectionStrategy.getId()), selectionStrategy,idsList);
                    if(CollUtil.isNotEmpty(questionAndAnswer)){
                        if(CollUtil.isNotEmpty(s.getQuestionTestPaperResultVos())){
                            List<QuestionTestPaperResultVo> questionTestPaperResultVos = s.getQuestionTestPaperResultVos();
                            questionTestPaperResultVos.addAll(questionAndAnswer);
                            s.setQuestionTestPaperResultVos(questionTestPaperResultVos);
                        }else{
                            s.setQuestionTestPaperResultVos(questionAndAnswer);
                        }
                    }
                }
            }
        });
    }

    private List<QuestionTestPaperResultVo> getQuestionAndAnswer(List<SelectionStrategyQuestion> questions, SelectionStrategy selectionStrategy, List<Integer> ids) {
        if(CollUtil.isEmpty(questions)){
            return null;
        }
        //是类型选题
        if(questions.size()==1&&questions.get(0).getSmallQuestionId()==null){
            LambdaQueryWrapper<SmallQuestion> w = new LambdaQueryWrapper<>();
            if(CollUtil.isNotEmpty(ids)){
                w.notIn(SmallQuestion::getId,ids);
            }
            w.eq(SmallQuestion::getQuestionType,questions.get(0).getQuestionType()).eq(SmallQuestion::getType, questions.get(0).getTopic());
            w.last(" order By Rand() limit "+selectionStrategy.getUnlimitedDifficulty());
            List<SmallQuestion> smallQuestions = smallQuestionService.list(w);
            w.clear();
            w.eq(SmallQuestion::getQuestionType,questions.get(0).getQuestionType()).eq(SmallQuestion::getType, questions.get(0).getTopic());
            w.last(" order By Rand() limit "+selectionStrategy.getEasily());
            List<SmallQuestion> smallQuestions2 = smallQuestionService.list(w);
            w.clear();
            w.eq(SmallQuestion::getQuestionType,questions.get(0).getQuestionType()).eq(SmallQuestion::getType, questions.get(0).getTopic());
            w.last(" order By Rand() limit "+selectionStrategy.getSecondary());
            List<SmallQuestion> smallQuestions3 = smallQuestionService.list(w);
            w.clear();
            w.eq(SmallQuestion::getQuestionType,questions.get(0).getQuestionType()).eq(SmallQuestion::getType, questions.get(0).getTopic());
            w.last(" order By Rand() limit "+selectionStrategy.getDifficulty());
            List<SmallQuestion> smallQuestions4 = smallQuestionService.list(w);
            smallQuestions.addAll(smallQuestions2);
            smallQuestions.addAll(smallQuestions3);
            smallQuestions.addAll(smallQuestions4);
            //将选项转换
            List<QuestionTestPaperResultVo> questionTestPaperResultVos = smallQuestions.stream().map(s -> {
                QuestionTestPaperResultVo questionTestPaperResultVo = BeanCopyUtils.copyBean(s, QuestionTestPaperResultVo.class);
                questionTestPaperResultVo.setScore(selectionStrategy.getScore());
                if (StrUtil.isNotBlank(s.getSmallQuestionAnswer())) {
                    questionTestPaperResultVo.setSmallQuestionAnswers(JSONArray.parseArray(s.getSmallQuestionAnswer(), SmallQuestionAnswer.class));
                }
                return questionTestPaperResultVo;
            }).collect(Collectors.toList());
            return questionTestPaperResultVos;

        }
        List<Integer> collect = questions.stream().map(SelectionStrategyQuestion::getSmallQuestionId).collect(Collectors.toList());
        LambdaQueryWrapper<SmallQuestion> w = new LambdaQueryWrapper<>();
        w.in(SmallQuestion::getId,collect);
        w.eq(SmallQuestion::getDifficultyLevel, 1);
        w.last(" order By Rand() limit "+selectionStrategy.getUnlimitedDifficulty());
        List<SmallQuestion> smallQuestions = smallQuestionService.list(w);
        w.clear();
        w.in(SmallQuestion::getId,collect);
        w.eq(SmallQuestion::getDifficultyLevel, 2);
        w.last(" order By Rand() limit "+selectionStrategy.getEasily());
        List<SmallQuestion> smallQuestions2 = smallQuestionService.list(w);
        w.clear();
        w.in(SmallQuestion::getId,collect);
        w.eq(SmallQuestion::getDifficultyLevel, 3);
        w.last(" order By Rand() limit "+selectionStrategy.getSecondary());
        List<SmallQuestion> smallQuestions3 = smallQuestionService.list(w);
        w.clear();
        w.in(SmallQuestion::getId,collect);
        w.eq(SmallQuestion::getDifficultyLevel, 4);
        w.last(" order By Rand() limit "+selectionStrategy.getDifficulty());
        List<SmallQuestion> smallQuestions4 = smallQuestionService.list(w);
        smallQuestions.addAll(smallQuestions2);
        smallQuestions.addAll(smallQuestions3);
        smallQuestions.addAll(smallQuestions4);

        //将选项转换
        List<QuestionTestPaperResultVo> questionTestPaperResultVos = smallQuestions.stream().map(s -> {
            QuestionTestPaperResultVo questionTestPaperResultVo = BeanCopyUtils.copyBean(s, QuestionTestPaperResultVo.class);
            questionTestPaperResultVo.setScore(selectionStrategy.getScore());
            if (StrUtil.isNotBlank(s.getSmallQuestionAnswer())) {
                questionTestPaperResultVo.setSmallQuestionAnswers(JSONArray.parseArray(s.getSmallQuestionAnswer(), SmallQuestionAnswer.class));
            }
            return questionTestPaperResultVo;
        }).collect(Collectors.toList());


        return questionTestPaperResultVos;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(List<Integer> ids) {
        if(CollUtil.isEmpty(ids)){
            return;
        }
        //1.删除试卷所有关联
        bigQuestionService.deleteByExaminationIds(ids);
        //1.1删除固定试卷所有问题
        fixedTestQuestionService.deleteByExaminationIds(ids);
        //1.2删除随机试卷所有关联
        selectionStrategyService.deleteByExaminationIds(ids);
        //2.删除试卷
        removeByIds(ids);
        //3.删除考试选择的试卷
        testinfoService.deleteByExaminationIds(ids);
    }
}
